package org.chnxi.study.concurrent.cyclicbarrier.demo1;

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {

    private static class Work implements Runnable{

        CyclicBarrier cyclicBarrier;

        public Work(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try{
                firstWork();
                cyclicBarrier.await(); // 完成业务一后进行等待
                secondWork();
                cyclicBarrier.await(); // 完成业务二后进行登台
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        // 模拟业务一
        private void firstWork(){
            System.out.println(Thread.currentThread().getName()+"完成执行第一项工作");
        }

        // 模拟业务二
        private void secondWork(){
            System.out.println(Thread.currentThread().getName()+"完成执行第二项工作");
        }
    }

    /**
     * 通知线程
     */
    private static class NoticeThread implements Runnable {

        boolean[] flag = new boolean[2];

        @Override
        public void run() {
            if(!flag[0]){
                System.out.println("通知：第一阶段工作完成");
                flag[0] = true;
            }else if(!flag[1]){
                System.out.println("通知：第二阶段工作完成");
                flag[1] = true;
            }
        }
    }

    /**
     * 执行结果：
     * T-0完成执行第一项工作
     * T-2完成执行第一项工作
     * T-1完成执行第一项工作
     * T-3完成执行第一项工作
     * T-4完成执行第一项工作
     * 通知：第一阶段工作完成
     * T-4完成执行第二项工作
     * T-1完成执行第二项工作
     * T-2完成执行第二项工作
     * T-0完成执行第二项工作
     * T-3完成执行第二项工作
     * 通知：第二阶段工作完成
     *
     * 从结果看到 cyclicBarrier 阻塞所有线程, 之后 都到达后 ,会唤醒一个通知线程, 之后所有阻塞的工作线程继续执行,
     * 都到达第二阶段 之后唤醒 通知线程,再继续. 并且一个 cyclicBarrier可以重复利用.
     */
    public static void main(String[] args) {
        CyclicBarrier cb = new CyclicBarrier(5 , new NoticeThread());
        for (int i=0; i<5; i++){
            new Thread(new Work(cb), "T-"+i).start();
        }
    }

}
